package conditionsAPI;

import java.util.Iterator;

/**
 * Clase que implementa And de las precondiciones configuradas en ComposedCondition.
 */
class AndCondition extends ComposedCondition{
	
	public AndCondition(String id) throws ConditionDuplicatedException{
		super(id);
	}

	public boolean arePreConditionsFulfilled() {
		if (preConditions.isEmpty())
			return false;
		
		if (this.conditionOrder){
			return this.areOrderlyPreConditionsFulfilled();
		} else {
			return this.areDisorderlyPreConditionsFulfilled();
		}
	}
	
	private boolean areDisorderlyPreConditionsFulfilled() {
		Iterator<Condition> preConditionsIterator = this.preConditions.iterator();
		while (preConditionsIterator.hasNext()){
			Condition condition = preConditionsIterator.next();
			if (! condition.isTrue()) {
				return false;
			}
		}
		return true;
	}
	
	private boolean areOrderlyPreConditionsFulfilled() {
		Iterator<Boolean> preConditionsOrderIterator = this.preConditionsOrder.values().iterator();
		while (preConditionsOrderIterator.hasNext()){
			Boolean conditionValue = preConditionsOrderIterator.next();
			if (! conditionValue){ 
				return false;
			}
		}
		return true;
	}
	
	protected void updateConditionState(Condition condition){
		if (this.conditionOrder){
			this.updateConditionOrderState(condition); 
		}
	}

	private void updateConditionOrderState(Condition condition) {
		if (this.arePreviousPreConditionsFulfilled(condition)){
			this.updatePreconditionsOrderState(condition);
		}
	}

	private void updatePreconditionsOrderState(Condition condition) {
		this.preConditionsOrder.put(condition.getId(), condition.isTrue());
		if (! condition.isTrue()) {
			this.updateFollowingPreConditionsOrderState(condition);
		}
	}
	
	private boolean arePreviousPreConditionsFulfilled(Condition condition) {
		boolean value = true;
		Iterator<Condition> preConditionsIterator = this.preConditions.iterator();
		while (preConditionsIterator.hasNext()){
			Condition conditionFromIterator = preConditionsIterator.next();
			if (! conditionFromIterator.equals(condition)){ 
				value = value & preConditionsOrder.get(conditionFromIterator.getId()).booleanValue();
			} else {
				return value;
			}
		}
		return false;
	}
	
	private void updateFollowingPreConditionsOrderState(Condition condition){
		boolean updateCondition = false;
		Iterator<Condition> preConditionsIterator = this.preConditions.iterator();
		while (preConditionsIterator.hasNext()){
			Condition conditionFromIterator = preConditionsIterator.next();
			if (updateCondition)
				preConditionsOrder.put(conditionFromIterator.getId(), false);
			if (conditionFromIterator.equals(condition))
				updateCondition = true;
		}
	}
}
